home *** CD-ROM | disk | FTP | other *** search
- //
- // Linear-Affine-Projective Geometry Package
- //
- // Map.C
- //
- // $Header$
- //
- // William J.R. Longabaugh
- // University of Washington
- //
- // Implementation of the linear-affine-projective geometry
- // package described in William J.R. Longabaugh, "An Expanded
- // System for Coordinate-Free Geometric Programming", Master's
- // thesis, University of Washington, 1992.
- //
- // Copyright (c) 1992, William J.R. Longabaugh
- // Copying, use and development for non-commercial purposes permitted.
- // All rights for commercial use reserved.
- // This software is unsupported and without warranty; it is
- // provided "as is".
- //
- // ***********************************************************************
-
- #include <math.h>
- #include "Lap.h"
-
- // ***********************************************************************
- // ***********************************************************************
- //
- // Map Class
- //
- // ***********************************************************************
- // ***********************************************************************
- //
- // Private/protected member functions
- //
- // ***********************************************************************
- //
- // This routine is used by map constructors to convert lists
- // of arbitrary geometric objects into objects of the desired type
- // in the desired space. A matrix containing std. coords of the
- // objects is built:
- //
-
- Boolean Map::ConvertList(GeObList& v, GeObType targ,
- SubSet& dest, Matrix* temp)
- {
- Space destspace = dest.EmbeddingSpace();
-
- // Determine if the matrix reps. need to be normalized:
-
- Boolean norm =
- ((destspace.Holds() == PROJ_SPACE) && (dest.Holds() == AFFINE_SUBSET));
-
- for (int i = 0; i < v.Length(); i++) {
- GeOb tempgeob = v[i].MapTo(targ);
- if (tempgeob.SpaceOf() != destspace) {
- return (FALSE);
- }
- if (!dest.IsIn(tempgeob)) {
- return (FALSE);
- }
- if (norm) {
- tempgeob = dest.Normalize(tempgeob);
- }
- (*temp)[i] = tempgeob.MatrixRep()[0];
- }
- return (TRUE);
- }
-
- // ***********************************************************************
- //
- // Apply associated linear map (without explicitly building it):
- //
-
- GeOb Map::ApplyAL(GeOb& v)
- {
- static char* sig = "GeOb Map::ApplyAL(void)";
-
- GeOb temp = v.MapTo(AFF_VECTOR);
- if (temp.SpaceOf() != domain.TangentSub().EmbeddingSpace()) {
- errh.ErrorExit(sig, "Object cannot be mapped to domain space", *this, v);
- }
- if (!domain.TangentSub().IsIn(temp)) {
- errh.ErrorExit(sig, "Mapped object not in specified domain subset",
- *this, temp);
- }
-
- // The range depends on the character of the affine map. If it is
- // to an affine subset of an affine space, the range is the
- // corresponding subspace of the tangent space. If it is to an
- // affine subset of a vector space, the range is a parallel vector
- // subspace of the vector space. If it is to a vector subset,
- // this range is the same vector subset.
-
- if (range.EmbeddingSpace().Holds() == AFF_SPACE) {
- Matrix alt = temp.MatrixRep() *
- domain.EmbeddingSpace().HoistTangent() * t;
- Matrix holdmatr = range.EmbeddingSpace().HoistTangent();
- GeOb retval(AFF_VECTOR, range.TangentSub().EmbeddingSpace(),
- alt * Transpose(holdmatr));
- return retval;
- } else {
- Matrix alt = temp.MatrixRep() *
- domain.EmbeddingSpace().HoistTangent() * t;
- GeOb retval(VECTOR, range.EmbeddingSpace(), alt);
- return retval;
- }
- }
-
- // ***********************************************************************
- //
- // Given all the information, builds a new Map
- //
-
- Map::Map(MapType ty, Boolean i, SubSet& r,
- SubSet& d, Matrix& tm, Matrix& it, Boolean isdf,
- Boolean hal, GeObType dt, GeObType rt) : range(r), domain(d),
- t(tm), invt(it)
- {
- invertible = i;
- type = ANY_MAP;
- holds = ty;
- hasAL = hal;
- isDefault = isdf;
- domtype = dt;
- rettype = rt;
- }
-
- // ***********************************************************************
- //
- // Dumps out all the data for a map:
- //
-
- void Map::data_out(ostream& c, int indent, char* name)
- {
- char *ibloc = new char[indent + 1];
- for (int i = 0; i < indent; i++) {
- *(ibloc + i) = ' ';
- }
- *(ibloc + indent) = '\0';
-
- c << ibloc << ast;
- c << ibloc << name;
- c << ibloc << "Type of map: ";
- MapTypeOut(c, type);
- c << "\n";
- c << ibloc << "Currently holds: ";
- MapTypeOut(c, holds);
- c << "\n";
- if (holds != NULL_MAP) {
- c << ibloc << "Domain subset:\n";
- domain.debug_out(c, indent + ERR_IND);
- c << ibloc << "Range subset:\n";
- range.debug_out(c, indent + ERR_IND);
- c << ibloc << "Matrix representation of map:\n";
- t.debug_out(c, indent + ERR_IND);
- c << ibloc << "Type of domain argument: ";
- GeObTypeOut(c, domtype);
- c << "\n" << ibloc << "Type of result: ";
- GeObTypeOut(c, rettype);
- if (invertible) {
- c << "\n" << ibloc << "Matrix representation of inverse:\n";
- invt.debug_out(c, indent + ERR_IND);
- } else {
- c << "\n" << ibloc << "Map is not invertible\n";
- }
- if (hasAL) {
- c << ibloc << "Map has an associated linear map\n";
- } else {
- c << ibloc << "Map does not have an associated linear map\n";
- }
- if (isDefault) {
- c << ibloc << "Map is a default map\n";
- } else {
- c << ibloc << "Map is not a default map\n";
- }
- }
- c << ibloc << ast;
-
- delete ibloc;
- return;
- }
-
- // ***********************************************************************
- //
- // Public member functions
- //
- // ***********************************************************************
- //
- // Need to do memberwise initialization, since matrix class members need
- // to do memberwise initialization:
- //
-
- Map::Map(Map &m) : range(m.range), domain(m.domain), t(m.t), invt(m.invt)
- {
- invertible = m.invertible;
- type = ANY_MAP;
- holds = m.holds;
- hasAL = m.hasAL;
- isDefault = m.isDefault;
- domtype = m.domtype;
- rettype = m.rettype;
- }
-
- // ***********************************************************************
- //
- // Need to do memberwise assignment, since Matrix class members need to
- // do memberwise assignment:
- //
-
- Map& Map::operator=(Map &m)
- {
- //
- // This weird checking is required to bypass the apparent inheritance of
- // assignment under g++ 1.37:
- //
- if ((type != ANY_MAP) && (type != m.holds) && (m.holds != NULL_MAP)) {
- errh.ErrorExit("Map& Map::operator=(Map&)",
- "Illegal assignment attempted", *this, m);
- }
- range = m.range;
- domain = m.domain;
- t = m.t;
- invt = m.invt;
- invertible = m.invertible;
- holds = m.holds;
- hasAL = m.hasAL;
- isDefault = m.isDefault;
- domtype = m.domtype;
- rettype = m.rettype;
- return (*this);
- }
-
- // ***********************************************************************
- //
- // Output for debugging:
- //
-
- void Map::debug_out(ostream &c, int indent)
- {
- static char* name = "Map Object\n";
- this->data_out(c, indent, name);
- return;
- }
-
- // ***********************************************************************
- //
- // If the MultiMap has an atomic VSpace or ASpace for a domain, it
- // can be converted to a map. Alternately, if it is a fully evaluated
- // map that evaluates to a vector, it can be converted to a map from
- // the dual space to the Reals.
- //
-
- Map::Map(MultiMap &m)
- {
- static char* sig = "Map::Map(MultiMap&)";
-
- type = ANY_MAP;
-
- if (m.FullyEvaluated()) {
- *this = Map(GeOb(m));
- } else {
-
- // Check that the domain is an atomic VSpace or ASpace:
-
- if (m.DomainSpace().CPSpaceSize() != 1) {
- errh.ErrorExit(sig, "Domain of multimap must be an atomic space", m);
- }
-
- holds = (m.Holds() == MULTI_LINEAR) ? LIN_MAP : AFF_MAP;
-
- range = m.RangeSpace().FullSet();
- domain = m.DomainSpace().FullSet();
- domtype = m.DomainType();
- rettype = m.RetType();
- isDefault = FALSE;
- hasAL = (domtype == AFF_POINT);
-
- int ddim = m.DomainSpace().MatrixSize();
- int rdim = m.RangeSpace().MatrixSize();
-
- t = Matrix(ddim, rdim);
- for (int i = 0; i < ddim; i++) {
- t[i] = (m.GetStdImage(i))[0];
- }
-
- if ((ddim == rdim) && (fabs(Det(t)) > EPSILON)) {
- invertible = TRUE;
- invt = Inverse(t);
- } else {
- invertible = FALSE;
- }
- }
- }
-
- // ***********************************************************************
- //
- // If the GeOb is a vector, it can be converted to a map from the
- // dual space to the Reals.
- //
-
- Map::Map(GeOb& g)
- {
- static char* sig = "Map::Map(GeOb&)";
- GeOb temp;
-
- type = ANY_MAP;
-
- if ((g.Holds() == VECTOR) || (g.Holds() == AFF_VECTOR)) {
- temp = g;
- } else if (g.CanMapTo(VECTOR)) {
- temp = g.MapTo(VECTOR);
- } else {
- errh.ErrorExit(sig, "GeOb cannot be mapped to a vector", g);
- }
-
- range = Reals.FullSet();
- domain = temp.SpaceOf().Dual().FullSet();
- t = Transpose(temp.MatrixRep());
-
- if (domain.EmbeddingSpace().Dim() == 1) {
- invt = Inverse(t);
- invertible = TRUE;
- } else {
- invertible = FALSE;
- }
-
- holds = LIN_MAP;
- hasAL = FALSE;
- isDefault = FALSE;
- domtype = domain.EmbeddingSpace().NativeType();
- rettype = VECTOR;
- }
-
- // ***********************************************************************
- //
- // Map application.
- //
- // It probably makes sense to also provide a special map application operator
- // (to the implementing classes ONLY) that assumes its argument is
- // the correct type and fills in a result at a location specified
- // by an argument pointer. This would help standard mappings be more
- // efficient.
- //
-
- GeOb Map::operator()(GeOb& v)
- {
- static char* sig = "GeOb Map::operator()(GeOb&)";
-
- if (v.CanMapTo(domtype)) {
- GeOb temp = v.MapTo(domtype);
- if (temp.SpaceOf() != domain.EmbeddingSpace()) {
- errh.ErrorExit(sig, "Object cannot be mapped to domain space", *this, v);
- }
- if (!domain.IsIn(temp)) {
- errh.ErrorExit(sig, "Mapped object not in specified domain subset",
- *this, temp);
- }
- if (domtype == PROJ_POINT && holds == AFF_MAP) {
- temp = domain.Normalize(temp);
- }
- Matrix retmat = temp.MatrixRep();
- if (!isDefault) {
- retmat = retmat * t;
- }
- GeOb retval(rettype, range.EmbeddingSpace(), retmat);
- return (retval);
- } else if (hasAL && v.CanMapTo(AFF_VECTOR)) {
- return (this->ApplyAL(v));
- } else {
- errh.ErrorExit(sig, "Object cannot be mapped into domain space",
- *this, v);
- }
- }
-
- // ***********************************************************************
- //
- // Since inverses are computed when the map is created, this is cheap.
- //
-
- Map Map::Inv(void)
- {
- static char* sig = "Map Map::Inv(void)";
-
- if (!invertible) {
- errh.ErrorExit(sig, "Map is not invertible", *this);
- }
- Boolean hal = ((holds == AFF_MAP) &&
- (domtype != PROJ_POINT) &&
- (rettype == AFF_POINT));
- Map retval(holds, invertible, domain, range, invt, t,
- isDefault, hal, rettype, domtype);
- return (retval);
- }
-
- // ***********************************************************************
- //
- // Composition of two maps of the same type:
- //
-
- Map Map::Compose(Map &m)
- {
- static char* sig = "Map Map::Compose(Map&)";
- Scalar factor = 1.0;
-
- if (holds == m.Holds()) {
- if (!domain.IsSubset(m.Range())) {
- errh.ErrorExit(sig,
- "Range of first map not a subset of domain of second map",
- *this, m);
- }
-
- // Affine maps into/outof projective spaces need a factor to account
- // for the need to normalize the offsets of the subsets:
-
- if ((domain.EmbeddingSpace().Holds() == PROJ_SPACE) &&
- (domain.Holds() == AFFINE_SUBSET)) {
- factor = domain.NormVal(m.Range());
- }
-
- Boolean cinv = invertible && m.Invertible() && m.Range().IsSubset(domain);
- Matrix ct = factor * m.t * t;
- Matrix cinvt;
- if (cinv) {
- cinvt = (1.0 / factor) * invt * m.invt;
- }
- GeObType cdt = m.DomainType();
- GeObType crt = rettype;
- Boolean chal = ((holds == AFF_MAP) &&
- (cdt == AFF_POINT) && (crt != PROJ_POINT));
- Boolean cisdf = isDefault && m.isDefault;
- Map retval(holds, cinv, range, m.Domain(), ct, cinvt,
- cisdf, chal, cdt, crt);
- return (retval);
- } else {
- errh.ErrorExit(sig, "Cannot compose different map types", *this, m);
- }
- }
-
- // ***********************************************************************
- //
- // A common operation in graphics programming is to compose affine
- // and projective maps to get a projective map. This operation
- // does this composition by automatically casting any affine maps
- // to projective maps:
- //
-
- ProjectiveMap Map::ComposeProj(Map &m)
- {
- ProjectiveMap first;
- ProjectiveMap second;
-
- if (holds == PROJ_MAP) {
- first = *this;
- } else {
- first = this->InducedProjective();
- }
-
- if (m.Holds() == PROJ_MAP) {
- second = m;
- } else {
- second = m.InducedProjective();
- }
-
- return (first.Compose(second));
- }
-
- // ***********************************************************************
- //
- // Given an affine map between two full affine spaces, we frequently desire
- // the corresponding projective map between the neighboring projective
- // completion spaces:
- //
-
- ProjectiveMap Map::InducedProjective(void)
- {
- static char* sig = "ProjectiveMap Map::InducedProjective(void)";
-
- // For the current implementation, restrict this operation to affine
- // maps between full affine subsets of affine spaces.
-
- if (holds != AFF_MAP) {
- errh.ErrorExit(sig,
- "Can only take induced projective map for an affine map", *this);
- }
-
- if ((range.EmbeddingSpace().Holds() != AFF_SPACE ) ||
- (domain.EmbeddingSpace().Holds() != AFF_SPACE ) ||
- (!range.IsFullSpace()) || (!domain.IsFullSpace())) {
- errh.ErrorExit(sig,
- "Only implemented for maps between full affine spaces",
- *this);
- }
-
- // Require that the map be invertible; otherwise, we would need to
- // build a special domain subset for the projective map:
-
- if (!invertible) {
- errh.ErrorExit(sig, "Map must be invertible", *this);
- }
-
- SubSet td = domain.EmbeddingSpace().GetSpace(PROJECT_COMP).FullSet();
- SubSet tr = range.EmbeddingSpace().GetSpace(PROJECT_COMP).FullSet();
- GeObType trt = PROJ_POINT;
- GeObType tdt = PROJ_POINT;
-
- Matrix newt = td.EmbeddingSpace().AffineMapTo(AFFINE).t * t *
- range.EmbeddingSpace().AffineMapTo(PROJECT_COMP).t;
-
- Matrix newinvt = tr.EmbeddingSpace().AffineMapTo(AFFINE).t * invt *
- domain.EmbeddingSpace().AffineMapTo(PROJECT_COMP).t;
-
- Map retval(PROJ_MAP, invertible, tr, td, newt, newinvt,
- FALSE, FALSE, tdt, trt);
- return retval;
- }
-
- // ***********************************************************************
- //
- // Given an affine map between two full affine spaces, this gives the
- // corresponding linear map between the neighboring linearization spaces:
- //
-
- LinearMap Map::InducedLinear(void)
- {
- static char* sig = "LinearMap Map::InducedLinear(void)";
-
- // For the current implementation, restrict this operation to affine
- // maps between full affine subsets of affine spaces.
-
- if (holds != AFF_MAP) {
- errh.ErrorExit(sig,
- "Can only take induced linear map for an affine map", *this);
- }
-
- if ((range.EmbeddingSpace().Holds() != AFF_SPACE ) ||
- (domain.EmbeddingSpace().Holds() != AFF_SPACE ) ||
- (!range.IsFullSpace()) || (!domain.IsFullSpace())) {
- errh.ErrorExit(sig,
- "Only implemented for maps between full affine spaces",
- *this);
- }
-
- SubSet td = domain.EmbeddingSpace().GetSpace(LINEARIZATION).FullSet();
- SubSet tr = range.EmbeddingSpace().GetSpace(LINEARIZATION).FullSet();
- GeObType trt = VECTOR;
- GeObType tdt = VECTOR;
-
- Matrix newt = td.EmbeddingSpace().AffineMapTo(AFFINE).t * t *
- range.EmbeddingSpace().AffineMapTo(LINEARIZATION).t;
-
- Matrix newinvt;
- if (invertible) {
- newinvt = tr.EmbeddingSpace().AffineMapTo(AFFINE).t * invt *
- domain.EmbeddingSpace().AffineMapTo(LINEARIZATION).t;
- }
-
- Map retval(LIN_MAP, invertible, tr, td, newt, newinvt,
- FALSE, FALSE, tdt, trt);
- return retval;
- }
-
- // ***********************************************************************
- //
- // The transpose of a map V -> U is a map U' -> V'. Currently only
- // implemented for maps between full spaces.
- //
-
- LinearMap Map::Trans(void)
- {
- static char* sig = "LinearMap Map::Trans(void)";
-
- // Make sure this map is linear:
-
- if (holds != LIN_MAP) {
- errh.ErrorExit(sig, "Can only take transpose of a linear map", *this);
- }
-
- if (!range.IsFullSpace() || !domain.IsFullSpace()) {
- errh.ErrorExit(sig,
- "Only implemented for maps between full spaces", *this);
- }
-
- // Need to get the dual subspaces for the range and domain,
- // and swap them:
-
- SubSet td = range.EmbeddingSpace().Dual().FullSet();
- SubSet tr = domain.EmbeddingSpace().Dual().FullSet();
- GeObType trt = tr.EmbeddingSpace().NativeType();
- GeObType tdt = td.EmbeddingSpace().NativeType();
-
- Map retval(LIN_MAP, invertible, tr, td, Transpose(t),
- Transpose(invt), FALSE, FALSE, tdt, trt);
- return retval;
- }
-
- // ***********************************************************************
- //
- // If this is map A -> X, with A a subset of an affine space and X a
- // subset of a linear or affine space, this is the map induced on the
- // tangent space A.v:
- //
-
- LinearMap Map::AssocLinear(void)
- {
- static char* sig = "LinearMap Map::AssocLinear(void)";
-
- // First need to make sure that the map has an associated linear map:
-
- if (!hasAL) {
- errh.ErrorExit(sig, "Map does not have an associated linear map", *this);
- }
-
- // Start to build matrix:
-
- Matrix hold = domain.EmbeddingSpace().HoistTangent();
- Matrix holdr = range.EmbeddingSpace().HoistTangent();
- Matrix alt = hold * t;
- Matrix alinvt;
- if (invertible) alinvt = invt * Transpose(hold);
-
- // The range depends on the character of the affine map. If it is
- // to an affine subset of an affine space, the range is the
- // corresponding subspace of the tangent space. If it is to an
- // affine subset of a vector space, the range is a vector
- // subspace in the vector space. If it is to a vector subset,
- // this range is the same vector subset.
-
- SubSet alr;
- GeObType alrt;
-
- if (range.EmbeddingSpace().Holds() == AFF_SPACE) {
- alr = range.TangentSub();
- alrt = AFF_VECTOR;
- alt = alt * Transpose(holdr);
- if (invertible) alinvt = holdr * alinvt;
- } else if (range.Holds() == AFFINE_SUBSET) {
- alr = range.TangentSub();
- alrt = VECTOR;
- } else {
- alr = range;
- alrt = VECTOR;
- }
-
- Map retval(LIN_MAP, invertible, alr, domain.TangentSub(), alt,
- alinvt, FALSE, FALSE, AFF_VECTOR, alrt);
- return retval;
- }
-
- // ***********************************************************************
- //
- // If this map is an affine functional (i.e. an affine map into the reals),
- // this returns the vector in the dual of the tangent space corresponding
- // to the associated linear map.
- //
-
- Vector Map::AssocDualVector(void)
- {
- static char* sig = "Vector Map::AssocDualVector(void)";
- Space res = range.EmbeddingSpace();
-
- if ((holds != AFF_MAP) || (res != Reals)) {
- errh.ErrorExit(sig, "Not an affine map into the Reals", *this);
- }
-
- Vector retval = Vector(this->AssocLinear());
- return (retval);
- }
-
-
-
- // ***********************************************************************
- // ***********************************************************************
- //
- // LinearMap Class
- //
- // ***********************************************************************
- // ***********************************************************************
- //
- // Public member functions
- //
- // ***********************************************************************
- //
- // A map can only be cast down to a Linear Map if it is one (no
- // conversions).
- //
-
- LinearMap::LinearMap(Map &m) : (m)
- {
- type = LIN_MAP;
- if ((holds != LIN_MAP) && (holds != NULL_MAP)) {
- errh.ErrorExit("LinearMap::LinearMap(Map &)",
- "Attempted to cast a non-linear map to a linear map", m);
- }
- }
-
- // ***********************************************************************
- //
- // Need to do memberwise assignment, since Matrix class members need to
- // do memberwise assignment:
- //
-
- LinearMap& LinearMap::operator=(LinearMap& m)
- {
- range = m.range;
- domain = m.domain;
- t = m.t;
- invt = m.invt;
- invertible = m.invertible;
- holds = m.holds;
- hasAL = m.hasAL;
- isDefault = m.isDefault;
- domtype = m.domtype;
- rettype = m.rettype;
- return (*this);
- }
-
- // ***********************************************************************
- //
- // Output for debugging:
- //
-
- void LinearMap::debug_out(ostream &c, int indent)
- {
- static char* name = "LinearMap Object\n";
- this->data_out(c, indent, name);
- return;
- }
-
- // ***********************************************************************
- //
- // Simplest kind of map creation. Since we are going between bases,
- // the map is invertible, and no subsets are involved:
- //
-
- LinearMap::LinearMap(VBasis &b1, VBasis &b2)
- {
- static char* sig = "LinearMap::LinearMap(VBasis&, VBasis&)";
-
- type = LIN_MAP;
- holds = LIN_MAP;
- domain = b1.SpaceOf().FullSet();
- range = b2.SpaceOf().FullSet();
- hasAL = FALSE;
- isDefault = FALSE;
- domtype = b1.SpaceOf().NativeType();
- rettype = b2.SpaceOf().NativeType();
-
- if (range.Dim() != domain.Dim()) {
- errh.ErrorExit(sig, "Range and domain do not have same dimension", b1, b2);
- }
-
- t = b1.Fromstdb() * b2.Tostdb();
- if (fabs(Det(t)) > EPSILON) {
- invt = Inverse(t);
- invertible = TRUE;
- } else {
- errh.ErrorExit(sig, "Unexpected error", b1, b2);
- }
- }
-
- // ***********************************************************************
- //
- // More general map creation. The domain of the map is a whole space,
- // but the range can be a subset. Each item in the GeObList represents
- // the image of the corresponding object in the basis.
-
- LinearMap::LinearMap(VBasis& b, VSubSet& s, GeObList& v)
- {
- static char* sig = "LinearMap::LinearMap(VBasis&, VSubSet&, GeObList&)";
- Space rspace = s.EmbeddingSpace();
-
- type = LIN_MAP;
- holds = LIN_MAP;
- domain = b.SpaceOf().FullSet();
- range = s;
- hasAL = FALSE;
- isDefault = FALSE;
- domtype = b.SpaceOf().NativeType();
- rettype = rspace.NativeType();
-
- // Make sure that enough image objects have been specified:
-
- if (v.Length() != domain.Dim()) {
- errh.ErrorExit(sig, "Incorrect number of objects specified", b, v);
- }
-
- // Map the objects into the range subset and use them to start building
- // the transform matrix:
-
- GeObType target = rspace.NativeType();
- Matrix temp(v.Length(), rspace.Dim());
-
- if (!(this->ConvertList(v, target, range, &temp))) {
- errh.ErrorExit(sig, "Object cannot be mapped into range subset", v, range);
- }
-
- // Build the transform matrix, and then start to build the inverse by
- // converting the range objects to the subspace basis representation:
-
- t = b.Fromstdb() * temp;
- temp = temp * range.FromFull();
-
- // Now figure out if the map is invertible. Two requirements must
- // be met. The dimension of the range and domain subsets must match,
- // and the specified image objects in the range must be independent.
-
- if (range.Dim() != domain.Dim()) {
- invertible = FALSE;
- } else {
- invertible = (fabs(Det(temp)) > EPSILON);
- }
-
- if (invertible) {
- invt = range.FromFull() * Inverse(temp) * b.Tostdb();
- }
- }
-
- // ***********************************************************************
- //
- // The reverse of the above constructor.
- //
-
- LinearMap::LinearMap(VSubSet &s, GeObList &v, VBasis &b)
- {
- static char* sig = "LinearMap::LinearMap(VSubSet&, GeObList&, VBasis&)";
- Space dspace = s.EmbeddingSpace();
-
- type = LIN_MAP;
- holds = LIN_MAP;
- domain = s;
- range = b.SpaceOf().FullSet();
- hasAL = FALSE;
- isDefault = FALSE;
- domtype = dspace.NativeType();
- rettype = b.SpaceOf().NativeType();
-
- // Make sure that enough preimage objects have been specified:
-
- if (v.Length() != range.Dim()) {
- errh.ErrorExit(sig, "Incorrect number of objects specified", b, v, s);
- }
- if (range.Dim() != domain.Dim()) {
- errh.ErrorExit(sig, "Domain and range dimensions do not match", v, s, b);
- }
-
- // Map the objects into the domain subset and use them to start building
- // the transform matrix:
-
- GeObType target = dspace.NativeType();
- Matrix temp1(v.Length(), dspace.Dim());
-
- if (!(this->ConvertList(v, target, domain, &temp1))) {
- errh.ErrorExit(sig,
- "Object cannot be mapped into domain subset", v, domain);
- }
-
- // We now need to confirm that the preimage objects we have been given
- // span the domain subset. If they do, build the transform matrix:
-
- Matrix temp2 = temp1 * domain.FromFull();
- if (fabs(Det(temp2)) <= EPSILON) {
- errh.ErrorExit(sig, "Objects in domain are not independent", v, s);
- }
- t = domain.FromFull() * Inverse(temp2) * b.Tostdb();
-
- // Maps built this way must be invertible, so build the inverse:
-
- invertible = TRUE;
- invt = b.Fromstdb() * temp1;
- }
-
- // ***********************************************************************
- //
- // Here is the most general linear map constructor.
- //
-
- LinearMap::LinearMap(VSubSet &s1, GeObList &v1, VSubSet &s2, GeObList &v2)
- {
- static char* sig =
- "LinearMap::LinearMap(VSubSet&, GeObList&, VSubSet&, GeObList&)";
- Space dspace = s1.EmbeddingSpace();
- Space rspace = s2.EmbeddingSpace();
-
- type = LIN_MAP;
- holds = LIN_MAP;
- domain = s1;
- range = s2;
- hasAL = FALSE;
- isDefault = FALSE;
- domtype = dspace.NativeType();
- rettype = rspace.NativeType();
-
- // Make sure that enough preimage and image objects have been specified:
-
- if (v1.Length() != domain.Dim()) {
- errh.ErrorExit(sig, "Incorrect number of objects specified", s1, v1);
- }
- if (v2.Length() != v1.Length()) {
- errh.ErrorExit(sig, "Incorrect number of objects specified", s1, s2, v2);
- }
-
- // Map the objects into the domain and range subsets and use them to start
- // building the transform matrix:
-
- GeObType target = dspace.NativeType();
- Matrix tempd(v1.Length(), dspace.Dim());
-
- if (!(this->ConvertList(v1, target, domain, &tempd))) {
- errh.ErrorExit(sig,
- "Object cannot be mapped into domain subset", v1, domain);
- }
-
- target = rspace.NativeType();
- Matrix tempr(v2.Length(), rspace.Dim());
-
- if (!(this->ConvertList(v2, target, range, &tempr))) {
- errh.ErrorExit(sig,
- "Object cannot be mapped into range subset", v2, range);
- }
-
- // We now need to confirm that the preimage objects we have been given
- // span the domain subset. If they do, build the transform matrix, and
- // then start to build the inverse by converting the range objects to
- // their subspace basis representation:
-
- Matrix tempd2 = tempd * domain.FromFull();
- if (fabs(Det(tempd2)) <= EPSILON) {
- errh.ErrorExit(sig, "Objects in domain are not independent", v1, s1);
- }
- t = domain.FromFull() * Inverse(tempd2) * tempr;
- tempr = tempr * range.FromFull();
-
- // Now figure out if the map is invertible. Two requirements must
- // be met. The dimension of the range and domain subsets must match,
- // and the specified image objects in the range must be independent.
-
- if (range.Dim() != domain.Dim()) {
- invertible = FALSE;
- } else {
- invertible = (fabs(Det(tempr)) > EPSILON);
- }
-
- if (invertible) {
- invt = range.FromFull() * Inverse(tempr) * tempd;
- }
- }
-
- // ***********************************************************************
- // ***********************************************************************
- //
- // AffineMap Class
- //
- // ***********************************************************************
- // ***********************************************************************
- //
- // Private/protected member functions
- //
- // ***********************************************************************
- //
- // Builds the default standard affine maps between spaces in a space set.
- //
-
- AffineMap::AffineMap(Space &s1, Space &s2)
- {
- static char* sig = "AffineMap::AffineMap(Space&, Space&)";
-
- // Standard affine maps go between standard affine subsets. Determine
- // if these spaces have defined subsets; create them if they do not,
- // get them if they do.
-
- domain = s1.StdAffineSubset();
- range = s2.StdAffineSubset();
-
- if (domain.Holds() == NULL_SUBSET) {
- domain = ASubSet(s1);
- }
-
- if (range.Holds() == NULL_SUBSET) {
- range = ASubSet(s2);
- }
-
- type = AFF_MAP;
- holds = AFF_MAP;
- invertible = TRUE;
- isDefault = TRUE;
- domtype = s1.NativeType();
- rettype = s2.NativeType();
-
- SRel s1t = s1.ThisSpaceIs();
- SRel s2t = s2.ThisSpaceIs();
- Space check = s1.GetSpace(s2t);
-
- if (check != s2) {
- errh.ErrorExit(sig, "Spaces are not linked", s1, s2);
- }
-
- hasAL = (s1t == AFFINE) && (s2t == LINEARIZATION);
- t = IdentityMatrix(s1.MatrixSize());
- invt = t;
- }
-
- // ***********************************************************************
- //
- // Builds a consistent affine map for linking an affine space to
- // a linearization space. USER IS RESPONSIBLE FOR COPYING STD.
- // AFFINE SUBSET GENERATED IN THIS ROUTINE TO THE EMBEDDING SPACE.
-
-
- AffineMap::AffineMap(AffineMap& apm, ProjectiveMap& lpm)
- {
- Space P = apm.Range().EmbeddingSpace();
- Space A = apm.Domain().EmbeddingSpace();
-
- // Linearization space needs a consistent standard affine subset.
-
- range = A.StdAffineSubset();
- domain = ASubSet(P.StdAffineSubset(), lpm.Inv());
- type = AFF_MAP;
- holds = AFF_MAP;
- invertible = TRUE;
- hasAL = FALSE;
- isDefault = FALSE;
- domtype = VECTOR;
- rettype = AFF_POINT;
-
- t = lpm.t * apm.invt;
- invt = Inverse(t);
- }
-
- // ***********************************************************************
- //
- // Builds a consistent affine map for linking an affine space to
- // a projective space:
- //
-
- AffineMap::AffineMap(ProjectiveMap& lpm, AffineMap& lam)
- {
- Space L = lpm.Domain().EmbeddingSpace();
- Space A = lam.Range().EmbeddingSpace();
-
- // Projective space does not yet have a standard affine subset. It
- // must be consistent with the linearization space standard affine
- // subset. USER IS RESPONSIBLE FOR COPYING STD.
- // AFFINE SUBSET GENERATED IN THIS ROUTINE TO THE EMBEDDING SPACE.
-
- domain = A.StdAffineSubset();
- range = ASubSet(L.StdAffineSubset(), lpm);
- type = AFF_MAP;
- holds = AFF_MAP;
- invertible = TRUE;
- hasAL = FALSE;
- isDefault = FALSE;
- domtype = AFF_POINT;
- rettype = PROJ_POINT;
-
- t = lam.invt * lpm.t;
- invt = Inverse(t);
- }
-
- // ***********************************************************************
- //
- // Public member functions
- //
- // ***********************************************************************
- //
- // A map can only be cast down to an affine map if it is one (no
- // conversions).
- //
-
- AffineMap::AffineMap(Map &m) : (m)
- {
- type = AFF_MAP;
- if ((holds != AFF_MAP) && (holds != NULL_MAP)) {
- errh.ErrorExit("AffineMap::AffineMap(Map&)",
- "Attempted to cast a non-affine map to an affine map", m);
- }
- }
-
- // ***********************************************************************
- //
- // Need to do memberwise assignment, since Matrix class members need to
- // do memberwise assignment.
- //
-
- AffineMap& AffineMap::operator=(AffineMap& m)
- {
- range = m.range;
- domain = m.domain;
- t = m.t;
- invt = m.invt;
- invertible = m.invertible;
- holds = m.holds;
- hasAL = m.hasAL;
- isDefault = m.isDefault;
- domtype = m.domtype;
- rettype = m.rettype;
- return (*this);
- }
-
- // ***********************************************************************
- //
- // Output for debugging:
- //
-
- void AffineMap::debug_out(ostream &c, int indent)
- {
- static char* name = "AffineMap Object\n";
- this->data_out(c, indent, name);
- return;
- }
-
- // ***********************************************************************
- //
- // Simplest kind of map creation. Since we are going between bases,
- // the map is invertible, and no subsets are involved. Restrict this
- // constructor to just handle maps between affine spaces (i.e. no
- // maps from simplex to vbasis).
- //
-
- AffineMap::AffineMap(Basis &b1, Basis &b2)
- {
- static char* sig = "AffineMap::AffineMap(Basis&, Basis&)";
-
- type = AFF_MAP;
- holds = AFF_MAP;
- domain = b1.SpaceOf().FullSet();
- range = b2.SpaceOf().FullSet();
- hasAL = TRUE;
- isDefault = FALSE;
- domtype = AFF_POINT;
- rettype = AFF_POINT;
-
- // Check that the type of basis matches:
-
- BasisType b1t = b1.Holds();
- BasisType b2t = b2.Holds();
-
- if ((b1t != b2t) || !((b1t == SIMPLEX) || (b1t == FRAME))) {
- errh.ErrorExit(sig, "Specified bases are not of the correct type", b1, b2);
- }
-
- // Check that the dimensionality matches:
-
- if (range.Dim() != domain.Dim()) {
- errh.ErrorExit(sig, "Range and domain do not have same dimension", b1, b2);
- }
-
- t = b1.Fromstdb() * b2.Tostdb();
- if (fabs(Det(t)) > EPSILON) {
- invt = Inverse(t);
- invertible = TRUE;
- } else {
- errh.ErrorExit(sig, "Unexpected error", b1, b2);
- }
- }
-
- // ***********************************************************************
- //
- // Map from a full affine space into some affine or vector subset.
- // We currently require that a simplex be used to define the domain
- // preimage.
- //
-
- AffineMap::AffineMap(Simplex& b, SubSet& s, GeObList& v)
- {
- static char* sig = "AffineMap::AffineMap(Simplex&, SubSet&, GeObList&)";
- Space rspace = s.EmbeddingSpace();
-
- type = AFF_MAP;
- holds = AFF_MAP;
- domain = b.SpaceOf().FullSet();
- range = s;
- domtype = AFF_POINT;
- rettype = rspace.NativeType();
- hasAL = (rettype != PROJ_POINT);
- isDefault = FALSE;
-
- // Make sure the subset is an affine or linear subset and that enough
- // image objects have been specified:
-
- if ((s.Holds() != LINEAR_SUBSET) && (s.Holds() != AFFINE_SUBSET)) {
- errh.ErrorExit(sig, "Specified subset is not linear or affine", s);
- }
- if (v.Length() != domain.Dim() + 1) {
- errh.ErrorExit(sig, "Incorrect number of objects specified", b, v);
- }
-
- // Map the objects into the range subset and use them to start building
- // the transform matrix:
-
- GeObType target = rspace.NativeType();
- Matrix temp(v.Length(), rspace.MatrixSize());
-
- if (!(this->ConvertList(v, target, range, &temp))) {
- errh.ErrorExit(sig, "Object cannot be mapped into range subset", v, range);
- }
-
- // Build the transform matrix, and then start to build the inverse by
- // converting the range objects to the subspace basis representation:
-
- t = b.Fromstdb() * temp;
- temp = temp * range.FromFull();
-
- // Now figure out if the map is invertible. Three requirements must
- // be met. The dimension of the range and domain subsets must match,
- // the range must be an affine subset, and the specified image objects
- // in the range must be independent.
-
- if ((range.Dim() != domain.Dim()) || (range.Holds() != AFFINE_SUBSET)) {
- invertible = FALSE;
- } else {
- invertible = (fabs(Det(temp)) > EPSILON);
- }
-
- if (invertible) {
- invt = range.FromFull() * Inverse(temp) * b.Tostdb();
- }
- }
-
- // ***********************************************************************
- //
- // Map from an affine subset to a full affine space.
- //
-
- AffineMap::AffineMap(ASubSet& s, GeObList& v, Simplex& b)
- {
- static char* sig = "AffineMap::AffineMap(ASubSet&, GeObList&, Simplex&)";
- Space dspace = s.EmbeddingSpace();
-
- type = AFF_MAP;
- holds = AFF_MAP;
- domain = s;
- range = b.SpaceOf().FullSet();
- domtype = dspace.NativeType();
- rettype = AFF_POINT;
- hasAL = (domtype == AFF_POINT);
- isDefault = FALSE;
-
- // Make sure the subset is an affine subset and that enough
- // preimage objects have been specified:
-
- if (v.Length() != range.Dim() + 1) {
- errh.ErrorExit(sig, "Incorrect number of objects specified", b, v, s);
- }
- if (range.Dim() != domain.Dim()) {
- errh.ErrorExit(sig, "Domain and range dimensions do not match", v, s, b);
- }
-
- // Map the objects into the domain subset and use them to start building
- // the transform matrix:
-
- GeObType target = dspace.NativeType();
- Matrix temp1(v.Length(), dspace.MatrixSize());
-
- if (!(this->ConvertList(v, target, domain, &temp1))) {
- errh.ErrorExit(sig,
- "Object cannot be mapped into domain subset", v, domain);
- }
-
- // We now need to confirm that the preimage objects we have been given
- // span the domain subset. If they do, build the transform matrix:
-
- Matrix temp2 = temp1 * domain.FromFull();
- if (fabs(Det(temp2)) <= EPSILON) {
- errh.ErrorExit(sig, "Objects in domain are not independent", v, s);
- }
- t = domain.FromFull() * Inverse(temp2) * b.Tostdb();
-
- // Maps built this way must be invertible, so build the inverse:
-
- invertible = TRUE;
- invt = b.Fromstdb() * temp1;
- }
-
- // ***********************************************************************
- //
- // Most general constructor for affine maps.
- //
-
- AffineMap::AffineMap(ASubSet &s1, GeObList &v1, SubSet &s2, GeObList &v2)
- {
- static char* sig =
- "AffineMap::AffineMap(ASubSet&, GeObList&, SubSet&, GeObList&)";
- Space dspace = s1.EmbeddingSpace();
- Space rspace = s2.EmbeddingSpace();
-
- type = AFF_MAP;
- holds = AFF_MAP;
- domain = s1;
- range = s2;
-
- domtype = dspace.NativeType();
- rettype = rspace.NativeType();
- hasAL = ((domtype == AFF_POINT) && (rettype != PROJ_POINT));
- isDefault = FALSE;
-
- // The range subspace can be either affine or linear. Also make
- // sure enough objects have been specified in each list:
-
- if ((s2.Holds() != LINEAR_SUBSET) && (s2.Holds() != AFFINE_SUBSET)) {
- errh.ErrorExit(sig, "Range subset is not linear or affine", s2);
- }
- if (v1.Length() != domain.Dim() + 1) {
- errh.ErrorExit(sig, "Incorrect number of objects specified", s1, v1);
- }
- if (v2.Length() != v1.Length()) {
- errh.ErrorExit(sig, "Incorrect number of objects specified", v1, s2, v2);
- }
-
- // Map the objects into the domain and range subsets and use them to start
- // building the transform matrix:
-
- GeObType target = dspace.NativeType();
- Matrix tempd(v1.Length(), dspace.MatrixSize());
-
- if (!(this->ConvertList(v1, target, domain, &tempd))) {
- errh.ErrorExit(sig,
- "Object cannot be mapped into domain subset", v1, domain);
- }
-
- target = rspace.NativeType();
- Matrix tempr(v2.Length(), rspace.MatrixSize());
-
- if (!(this->ConvertList(v2, target, range, &tempr))) {
- errh.ErrorExit(sig,
- "Object cannot be mapped into range subset", v2, range);
- }
-
- // We now need to confirm that the preimage objects we have been given
- // span the domain subset. If they do, build the transform matrix, and
- // then start to build the inverse by converting the range objects to
- // their subspace basis representation:
-
- Matrix tempd2 = tempd * domain.FromFull();
- if (fabs(Det(tempd2)) <= EPSILON) {
- errh.ErrorExit(sig, "Objects in domain are not independent", v1, s1);
- }
- t = domain.FromFull() * Inverse(tempd2) * tempr;
- tempr = tempr * range.FromFull();
-
- // Now figure out if the map is invertible. Two requirements must
- // be met. The dimension of the range and domain subsets must match,
- // and the specified image objects in the range must be independent.
-
- if (range.Dim() != domain.Dim()) {
- invertible = FALSE;
- } else {
- invertible = (fabs(Det(tempr)) > EPSILON);
- }
-
- if (invertible) {
- invt = range.FromFull() * Inverse(tempr) * tempd;
- }
- }
-
- // ***********************************************************************
- // ***********************************************************************
- //
- // ProjectiveMap Class
- //
- // ***********************************************************************
- // ***********************************************************************
- //
- // Private/protected member functions
- //
- // ***********************************************************************
- //
- // A core problem when constructing projective maps is scaling the
- // rows of the transformation matrix so the "extra" point maps
- // to its image. This routine scales the rows of a matrix so the
- // specified "unit point" matrix is the sum of the rows. It does this
- // by solving a system of equations:
- //
-
- Boolean ProjectiveMap::ScaleRows(Matrix* mat, Matrix& unit_pt)
- {
- if (fabs(Det(*mat)) < EPSILON) {
- return (FALSE);
- }
- Matrix invmat = Inverse(*mat);
-
- // Solve for the row coefficients. If any coefficient = 0, the
- // unit point was not in general position. Otherwise, multiply
- // the matrix rows by the coefficients, and report the success:
-
- Matrix coeff = unit_pt * invmat;
- for (int i = 0; i < coeff.Columns(); i++) {
- if (fabs(coeff[0][i]) < EPSILON) {
- return (FALSE);
- } else {
- (*mat)[i] = (coeff[0][i] * (*mat)[i])[0];
- }
- }
- return (TRUE);
- }
-
- // ***********************************************************************
- //
- // Similar to the general ConvertList routine, but sticks the last
- // object into a separate Matrix:
- //
-
- Boolean ProjectiveMap::ConvertListUnit(GeObList& v, GeObType trg, SubSet& d,
- Matrix* temp, Matrix* unit)
- {
- Space destspace = d.EmbeddingSpace();
-
- for (int i = 0; i < v.Length(); i++) {
- GeOb hold = v[i].MapTo(trg);
- if (hold.SpaceOf() != destspace) {
- return (FALSE);
- }
- if (!d.IsIn(hold)) {
- return (FALSE);
- }
- if (i == v.Length() - 1) {
- (*unit)[0] = hold.MatrixRep()[0];
- } else {
- (*temp)[i] = hold.MatrixRep()[0];
- }
- }
- return (TRUE);
- }
-
-
- // ***********************************************************************
- //
- // Builds the default standard projective maps between spaces in a space set.
- // One space must be projective, the other a linearization space.
-
- ProjectiveMap::ProjectiveMap(Space& s1, Space& s2)
- {
- static char* sig = "ProjectiveMap::ProjectiveMap(Space&, Space&)";
-
- domain = s1.FullProjSet();
- range = s2.FullProjSet();
-
- type = PROJ_MAP;
- holds = PROJ_MAP;
- invertible = TRUE;
- hasAL = FALSE;
- isDefault = TRUE;
- domtype = domain.Accepts();
- rettype = range.Accepts();
-
- SRel s1t = s1.ThisSpaceIs();
- SRel s2t = s2.ThisSpaceIs();
- Space check = s1.GetSpace(s2t);
-
- if (check != s2) {
- errh.ErrorExit(sig, "Spaces are not linked", s1, s2);
- }
-
- t = IdentityMatrix(s1.MatrixSize());
- invt = t;
- }
-
- // ***********************************************************************
- //
- // Builds a consistent projective map for linking a projective space to
- // a linearization space.
- //
-
- ProjectiveMap::ProjectiveMap(VSpace& L, AffineMap& lpm, PSpace& P)
- {
- domain = L.FullProjSet();
- range = P.FullSet();
- type = PROJ_MAP;
- holds = PROJ_MAP;
- invertible = TRUE;
- hasAL = FALSE;
- isDefault = lpm.isDefault;
- domtype = VEC_EC;
- rettype = PROJ_POINT;
-
- t = lpm.t;
- invt = Inverse(t);
- }
-
- // ***********************************************************************
- //
- // Public member functions
- //
- // ***********************************************************************
- //
- // A map can only be cast down to a Projective Map if it is one (no
- // conversions).
-
- ProjectiveMap::ProjectiveMap(Map &m) : (m)
- {
- type = PROJ_MAP;
- if ((holds != PROJ_MAP) && (holds != NULL_MAP)) {
- errh.ErrorExit("ProjectiveMap::ProjectiveMap(Map&)",
- "Attempted to cast a non-projective map to a projective map", m);
- }
- }
-
- // ***********************************************************************
- //
- // Need to do memberwise assignment, since Matrix class members need to
- // do memberwise assignment:
- //
-
- ProjectiveMap& ProjectiveMap::operator=(ProjectiveMap& m)
- {
- range = m.range;
- domain = m.domain;
- t = m.t;
- invt = m.invt;
- invertible = m.invertible;
- holds = m.holds;
- hasAL = m.hasAL;
- isDefault = m.isDefault;
- domtype = m.domtype;
- rettype = m.rettype;
- return (*this);
- }
-
- // ***********************************************************************
- //
- // Debug output
- //
-
- void ProjectiveMap::debug_out(ostream &c, int indent)
- {
- static char* name = "ProjectiveMap Object\n";
- this->data_out(c, indent, name);
- return;
- }
-
- // ***********************************************************************
- //
- // Used for invertible maps between whole projective spaces:
- //
-
- ProjectiveMap::ProjectiveMap(HFrame &b1, HFrame &b2)
- {
- static char* sig = "ProjectiveMap::ProjectiveMap(HFrame&, HFrame&)";
-
- type = PROJ_MAP;
- holds = PROJ_MAP;
- domain = b1.SpaceOf().FullSet();
- range = b2.SpaceOf().FullSet();
- hasAL = FALSE;
- isDefault = FALSE;
- domtype = PROJ_POINT;
- rettype = PROJ_POINT;
-
- // Check that the type of basis matches:
-
- if ((b1.Holds() != HFRAME) || (b2.Holds() != HFRAME)) {
- errh.ErrorExit(sig, "Specified bases are not projective frames", b1, b2);
- }
-
- // Check that the dimensionality matches:
-
- if (range.Dim() != domain.Dim()) {
- errh.ErrorExit(sig, "Range and domain do not have same dimension", b1, b2);
- }
-
- t = b1.Fromstdb() * b2.Tostdb();
- if (fabs(Det(t)) > EPSILON) {
- invt = Inverse(t);
- invertible = TRUE;
- } else {
- errh.ErrorExit(sig, "Unexpected error", b1, b2);
- }
- }
-
- // ***********************************************************************
- //
- // Used for invertible maps from a whole projective space to
- // a projective subset. Since the only allowable method for
- // creating non-invertible maps is to have a domain subset with
- // removed points, we require the image objects to be independent.
- // Note that the subset could be from a vector space. The range
- // subset cannot have removed points, since there would be no way
- // of returning a unique point in the embedding space.
- //
-
- ProjectiveMap::ProjectiveMap(HFrame &b, PSubSet &s, GeObList &v)
- {
- static char* sig =
- "ProjectiveMap::ProjectiveMap(HFrame&, PSubSet&, GeObList&)";
- Space rspace = s.EmbeddingSpace();
-
- type = PROJ_MAP;
- holds = PROJ_MAP;
- domain = b.SpaceOf().FullSet();
- range = s;
- hasAL = FALSE;
- isDefault = FALSE;
- domtype = PROJ_POINT;
- rettype = s.Accepts();
-
- // Make that enough image objects have been specified. Also, since
- // only invertible maps can be specified, check the dimensions:
-
- if (v.Length() != domain.Dim() + 2) {
- errh.ErrorExit(sig, "Incorrect number of objects specified", b, v);
- }
- if (range.Dim() != domain.Dim()) {
- errh.ErrorExit(sig, "Range and domain dimensions must be equal",
- range, domain);
- }
- if (range.HasRemovedPoints()) {
- errh.ErrorExit(sig, "Range subset cannot have removed points", range);
- }
-
- // Map the objects into the range subset and use them to start building
- // the transform matrix:
-
- int rdim = rspace.MatrixSize();
- Matrix temp(v.Length() - 1, rdim);
- Matrix unit(1, rdim);
-
- if (!(this->ConvertListUnit(v, rettype, range, &temp, &unit))) {
- errh.ErrorExit(sig, "Object cannot be mapped into range subset", v, range);
- }
-
- // Convert the range objects to the range subset basis representation, then
- // scale the matrix rows:
-
- temp = temp * range.FromFull();
- unit = unit * range.FromFull();
- if (!(this->ScaleRows(&temp, unit))) {
- errh.ErrorExit(sig, "Range objects not in general position", v, s);
- }
-
- // Build the transform matrix, then build the inverse:
-
- t = b.Fromstdb() * temp * range.ToFull();
- invt = range.FromFull() * Inverse(temp) * b.Tostdb();
- invertible = TRUE;
- }
-
- // ***********************************************************************
- //
- // Used for map from a projective subset to a projective space. If
- // subset has removed points, map will be non-invertible:
- //
-
- ProjectiveMap::ProjectiveMap(PSubSet &s, GeObList &v, HFrame &b)
- {
- static char* sig =
- "ProjectiveMap::ProjectiveMap(PSubSet&, GeObList&, HFrame&)";
- Space dspace = s.EmbeddingSpace();
-
- type = PROJ_MAP;
- holds = PROJ_MAP;
- domain = s;
- range = b.SpaceOf().FullSet();
- hasAL = FALSE;
- isDefault = FALSE;
- domtype = s.Accepts();
- rettype = PROJ_POINT;
-
- // Make sure that enough preimage objects have been specified.
- // Check that the domain and range dimensions match.
-
- if (v.Length() != range.Dim() + 2) {
- errh.ErrorExit(sig, "Incorrect number of objects specified", b, v, s);
- }
- if (range.Dim() != domain.Dim()) {
- errh.ErrorExit(sig, "Domain and range dimensions do not match", v, s, b);
- }
-
- // Map the objects into the domain subset and use them to start building
- // the transform matrix:
-
- int ddim = dspace.MatrixSize();
- Matrix temp(v.Length() - 1, ddim);
- Matrix unit(1, ddim);
-
- if (!(this->ConvertListUnit(v, domtype, domain, &temp, &unit))) {
- errh.ErrorExit(sig,
- "Object cannot be mapped into domain subset", v, domain);
- }
-
- // Convert the domain objects to the domain subset basis representation, then
- // scale the matrix rows:
-
- temp = temp * domain.FromFull();
- unit = unit * domain.FromFull();
- if (!(this->ScaleRows(&temp, unit))) {
- errh.ErrorExit(sig, "Domain objects not in general position", v, s);
- }
-
- // Build the transform matrix:
-
- t = domain.FromFull() * Inverse(temp) * b.Tostdb();
-
- // The invertibility of this transform depends on whether the domain
- // subset has been defined to have removed points. If it has, the
- // map is not invertible. Otherwise, calculate the inverse:
-
- invertible = !domain.HasRemovedPoints();
-
- if (invertible) {
- invt = b.Fromstdb() * temp * domain.ToFull();
- }
- }
-
- // ***********************************************************************
- //
- // Used for maps between subsets. If domain subset has removed points,
- // map will not be invertible:
- //
-
- ProjectiveMap::ProjectiveMap(PSubSet &s1, GeObList &v1,
- PSubSet &s2, GeObList &v2)
- {
- static char* sig =
- "ProjectiveMap::ProjectiveMap(PSubSet&, GeObList&, PSubSet&, GeObList&)";
- Space dspace = s1.EmbeddingSpace();
- Space rspace = s2.EmbeddingSpace();
-
- type = PROJ_MAP;
- holds = PROJ_MAP;
- domain = s1;
- range = s2;
- hasAL = FALSE;
- isDefault = FALSE;
- domtype = s1.Accepts();
- rettype = s2.Accepts();
-
- // Make sure that enough preimage and image objects have been specified.
- // Check that the domain and range dimensions match.
-
- if (v1.Length() != domain.Dim() + 2) {
- errh.ErrorExit(sig, "Incorrect number of objects specified", v1, s1);
- }
- if (v2.Length() != range.Dim() + 2) {
- errh.ErrorExit(sig, "Incorrect number of objects specified", v2, s2);
- }
- if (range.Dim() != domain.Dim()) {
- errh.ErrorExit(sig, "Domain and range dimensions do not match", s1, s2);
- }
- if (range.HasRemovedPoints()) {
- errh.ErrorExit(sig, "Range subset cannot have removed points", range);
- }
-
- // Map the objects into the domain and range subsets and use them to start
- // building the transform matrix:
-
- int ddim = dspace.MatrixSize();
- Matrix tempd(v1.Length() - 1, ddim);
- Matrix unitd(1, ddim);
- if (!(this->ConvertListUnit(v1, domtype, domain, &tempd, &unitd))) {
- errh.ErrorExit(sig,
- "Object cannot be mapped into domain subset", v1, domain);
- }
-
- int rdim = rspace.MatrixSize();
- Matrix tempr(v2.Length() - 1, rdim);
- Matrix unitr(1, rdim);
- if (!(this->ConvertListUnit(v2, rettype, range, &tempr, &unitr))) {
- errh.ErrorExit(sig,
- "Object cannot be mapped into range subset", v2, range);
- }
-
- // Convert the domain objects to the domain subset basis representation, then
- // scale the matrix rows. Do the same for the range:
-
- tempd = tempd * domain.FromFull();
- unitd = unitd * domain.FromFull();
- if (!(this->ScaleRows(&tempd, unitd))) {
- errh.ErrorExit(sig, "Domain objects not in general position", v1, s1);
- }
-
- tempr = tempr * range.FromFull();
- unitr = unitr * range.FromFull();
- if (!(this->ScaleRows(&tempr, unitr))) {
- errh.ErrorExit(sig, "Range objects not in general position", v2, s2);
- }
-
- // Build the transform matrix:
-
- t = domain.FromFull() * Inverse(tempd) * tempr * range.ToFull();
-
- // The invertibility of this transform depends on whether the domain
- // subset has been defined to have removed points. If it has, the
- // map is not invertible. Otherwise, calculate the inverse:
-
- invertible = !domain.HasRemovedPoints();
-
- if (invertible) {
- invt = range.FromFull() * Inverse(tempr) * tempd * domain.ToFull();
- }
- }
- // ***********************************************************************
-